package com.czk.plugins;

import com.czk.anotation.Desensitization;
import com.czk.desensitization.DesensitizationStrategy;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.sql.Statement;
import java.util.List;
import java.util.stream.Stream;

/**
 * 脱敏拦截器
 *
 * @Author:ChenZhangKun
 * @Date: 2021/4/18 14:22
 */
@Intercepts(@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = Statement.class))
@Component
@Order(1)
// 这对结果集进行处理，指定拦截的方法和参数
public class DesensitizationPlugin implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 首先调用业务方法，拿到结果
        List<Object> records = (List<Object>) invocation.proceed();
        // 进行脱敏处理
        records.forEach(this::desensitization);
        return records;
    }

    private void desensitization(Object source) {
        // 拿到类型
        Class<?> clazz = source.getClass();
        // 拿到元数据
        MetaObject metaObject = SystemMetaObject.forObject(source);
        Stream.of(clazz.getDeclaredFields()).filter(field -> field.isAnnotationPresent(Desensitization.class))
                .forEach(field -> doDesensitization(metaObject, field));
    }

    private void doDesensitization(MetaObject metaObject, Field field) {
        // 拿到名字
        String name = field.getName();
        // 拿到值
        Object value = metaObject.getValue(name);
        // 判断
        if (String.class == metaObject.getGetterType(name) && value != null) {
            // 拿到注解本身
            Desensitization annotation = field.getAnnotation(Desensitization.class);
            // 获取策略
            DesensitizationStrategy strategy = annotation.strategy();
            // 进行脱敏
            Object apply = strategy.getDesensitizer().apply((String) value);
            // 设置回元数据
            metaObject.setValue(name, apply);
        }
    }
}
